/**
 *
 */
package cn.xuqiudong.elasticsearch.autoconfigure;

import cn.xuqiudong.elasticsearch.helper.EsDocumentHelper;
import cn.xuqiudong.elasticsearch.helper.EsSearchHelper;
import cn.xuqiudong.elasticsearch.helper.IndexHelper;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.util.Asserts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.stream.Stream;

/**
 * 说明 :  ElasticSearch 自动装配入口
 * @author Vic.xu
 * @since  2020年9月10日下午5:51:12
 */
@Configuration
//设置个开关
@ConditionalOnExpression("${es.enabled:true}")
@ConditionalOnClass(value = RestHighLevelClient.class)
@EnableConfigurationProperties(value = EsProperties.class)
public class EsAutoconfigure {

    private static Logger logger = LoggerFactory.getLogger(EsAutoconfigure.class);

    @Autowired
    private EsProperties esProperties;

    RestHighLevelClient restHighLevelClient;

    IndexHelper indexHelper;

    /**
     * 创建RestHighLevelClient
     *
     * @link https://juejin.im/post/5d6238b351882559c416112f
     * @return RestHighLevelClient
     */
    @Bean
    @Primary
    public RestHighLevelClient restHighLevelClient() {
        if (restHighLevelClient != null) {
            return restHighLevelClient;
        }
        RestClientBuilder restClientBuilder = RestClient.builder(this.createHttpHost());
        restClientBuilder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
            @Override
            public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
                return requestConfigBuilder.setSocketTimeout(esProperties.getTimeout());
            }
        });
        this.restHighLevelClient = new RestHighLevelClient(restClientBuilder);
        return restHighLevelClient;
    }

    /**
     * 创建 IndexHelper index操作工具类
     * @return IndexHelper
     */
    @Bean
    public IndexHelper indexHelper() {
        if (this.indexHelper != null) {
            return this.indexHelper;
        }
        this.indexHelper = new IndexHelper(restHighLevelClient());
        return indexHelper;
    }

    /**
     * 创建EsDocumentHelper 方便对文档的一些 操作
     */
    @Bean
    public EsDocumentHelper esDocumentHelper() {
        return new EsDocumentHelper(restHighLevelClient());
    }

    /**
     * 创建EsSearchHelper  es搜索操作
     */
    @Bean
    public EsSearchHelper esSearchHelper() {
        return new EsSearchHelper(restHighLevelClient());
    }

    /**
     * 项目启动后创建索引，若不存在的情况下
     * @throws IOException
     */
    @PostConstruct
    public void initIndex() throws IOException {
        logger.info("into initIndex...................................");
        IndexConfig[] indexes = esProperties.getIndexes();
        if (indexes == null || indexes.length == 0) {
            return;
        }
        IndexHelper indexHelper = indexHelper();
        int length = indexes.length;
        int existNum = 0;
        int createdNum = 0;
        logger.info("配置的index数目为[{}]", length);
        for (int i = 0; i < length; i++) {
            IndexConfig config = indexes[i];
            if (indexHelper.isExistIndex(config.getName())) {
                existNum++;
                continue;
            }
            logger.info("索引{}不存在, 开始创建!", config.getName());
            indexHelper.createIndex(config);
            createdNum++;
            logger.info("索引{}创建成功!", config.getName());
        }

        logger.info("initIndex finished, existNum=[{}], createdNum=[{}]", existNum, createdNum);
    }

    /**
     * 项目关闭的时候关闭客户端
     */
    @PreDestroy
    public void closeClient() throws IOException {
        logger.info("关闭restHighLevelClient客户端");
        restHighLevelClient().close();
    }

    /**
     * 创建 HttpHost[] 对象
     *
     * @return 返回 HttpHost 对象数组
     */
    private HttpHost[] createHttpHost() {
        AddressConfig[] address = esProperties.getAddress();
        Asserts.check(!CollectionUtils.isEmpty(address), "ElasticSearch cluster ip address cannot empty");
        HttpHost[] hosts = Stream.of(address).map(addr -> {
            // 此处不校验数据的准确性
            return new HttpHost(addr.getIp(), addr.getPort(), esProperties.getScheme());
        }).toArray(HttpHost[]::new);
        return hosts;
    }

}
